package com.chianghao.rockframewrok.auth.core.token.impl;

import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.chianghao.rockframewrok.auth.core.token.ITokenCache;
import com.chianghao.rockframewrok.auth.core.token.ITokenHandle;
import com.chianghao.rockframewrok.auth.core.token.model.JWTToken;
import com.chianghao.rockframewrok.auth.core.token.model.Token;
import com.chianghao.rockframewrok.core.utils.StringUtils;

public class JWTTokenHandleImpl implements ITokenHandle<JWTToken> {

	/**
	 * // 秘钥
	 */
	private static final String SECRET = "0123456789abcdef";


	private static JWTTokenHandleImpl handle ;
	
	private ITokenCache tokenCache;
	
	private JWTTokenHandleImpl(ITokenCache tokenCache) {
		this.tokenCache = tokenCache;
		tokenCache.cleanExpToken();
	}
	
	public synchronized static JWTTokenHandleImpl get(ITokenCache tokenCache) {
		if(handle==null) {
			handle = new JWTTokenHandleImpl(tokenCache);
		}
		return handle;
	}
	
	@Override
	public JWTToken parseToken(String content) {
		if(StringUtils.isEmpty(content)) {
			return null;
		}
		Algorithm algorithm = null;
		try {
			algorithm = Algorithm.HMAC256(SECRET);
		} catch (IllegalArgumentException e) {
			throw new RuntimeException(e);
		}
		JWTVerifier verifier = JWT.require(algorithm).build();
		DecodedJWT jwt = null;
		try{
			jwt = verifier.verify(content);
		}catch(TokenExpiredException e){
			throw new RuntimeException(e);
		}
		String id = jwt.getId();
		// 如果缓存没有则表示后台删除
		Token cacheToken  = this.tokenCache.get(id);
		if(cacheToken==null) {
			return null;
		}
		
		JWTToken token  = new JWTToken();
		token.setAud(jwt.getAudience());
		token.setExp(jwt.getExpiresAt());
		token.setIat(jwt.getIssuedAt());
		token.setIss(jwt.getIssuer());
		token.setJti(jwt.getId());
		token.setNbf(jwt.getNotBefore());
		token.setSub(jwt.getSubject());
		Map<String, Claim>  claims  = jwt.getClaims();
		for(Entry<String, Claim> entry:claims.entrySet()) {
			token.setClaim(entry.getKey(), entry.getValue().asString());
		}
		
		
		return token;
	}

	@Override
	public String getToken(JWTToken token) {
		if(StringUtils.isEmpty(token.getJti())) {
			String jwtId = UUID.randomUUID().toString();
			token.setJti(jwtId);
		}
		Algorithm algorithm = Algorithm.HMAC256(SECRET);
		JWTCreator.Builder builder = JWT.create();
		if(token.getAud()!=null&&token.getAud().size()>0) {
			builder.withAudience(token.getAud().toArray(new String[token.getAud().size()]));
		}
		if(token.getExp()!=null) {
			builder.withExpiresAt(token.getExp());
		}
		if(token.getIss()!=null) {
			builder.withIssuer(token.getIss());
		}
		if(token.getIat()!=null) {
			builder.withIssuedAt(token.getIat());
		}
		if(token.getJti()!=null) {
			builder.withJWTId(token.getJti());
		}
		if(token.getNbf()!=null) {
			builder.withNotBefore(token.getNbf());
		}
		if(token.getSub()!=null) {
			builder.withSubject(token.getSub());
		}
		if(token.getCliaimMap()!=null) {
			for(Entry<String, String> entry:token.getCliaimMap().entrySet()) {
				token.setClaim(entry.getKey(), entry.getValue());
			}
		}
		
		// 向后台添加缓存
		this.tokenCache.put(token);
		return builder.sign(algorithm).toString();
	}

	@Override
	public void removeToken(String id) {
		this.tokenCache.remove(id);
	}

	
}
